/**
 * @author : dormi330
 * @version : 1.0
 * description : 文件描述
 */

package org.dormi.learn.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.dormi.learn.BaseSerializable;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.List;
import java.util.Locale;


public final class JsonSerializer {

    public final static String DEFALUT_TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /** ObjectMapper 线程安全, 公用一个节约性能 */
    public final static ObjectMapper objectMapper = new ObjectMapper();

    static {
        // new module, NOT JSR310Module 支持 LocalDateTime 等类型
        LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFALUT_TIMESTAMP_FORMAT));
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFALUT_TIMESTAMP_FORMAT)));
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFALUT_TIMESTAMP_FORMAT)));
        objectMapper.registerModule(new ParameterNamesModule())
                .registerModule(javaTimeModule)
                .registerModule(new JavaTimeModule());

        /** 在反序列化时忽略在 json 中存在但 Java 对象不存在的属性  */
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        /** 在序列化时日期格式 */
        DateFormat df = new SimpleDateFormat(DEFALUT_TIMESTAMP_FORMAT, Locale.CHINA);
        objectMapper.setDateFormat(df);

        /** 在序列化时忽略值为 null 的属性  */
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }

    private static String objectToJson(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException ex) {
            throw new RuntimeException("object -> json 异常", ex);
        }
    }

    private static String objectToPrettyJson(Object obj) {
        try {
            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (JsonProcessingException ex) {
            throw new RuntimeException("object -> json 异常", ex);
        }
    }

    /**
     * 返回一个 定制(日期/排除序列化字段)的 Gson对象, 用于进行 序列化/反序列化
     *
     * @return gosn对象
     */
    public static String prettyJson(Object obj) {
        return objectToPrettyJson(obj);
    }

    public static String toJson(Object obj) {
        return objectToJson(obj);
    }

    /** json string -> 对象 */
    public static <T> T jsonToObj(String json, Class<T> type) {
        if (null == json) {
            return null;
        }

        try {
            return objectMapper.readValue(json, type);
        } catch (IOException ex) {
            throw new RuntimeException("json -> object 异常", ex);
        }
    }

    public static <T> T jsonToObj(String json, TypeReference<T> typeReference) {
        try {
            return objectMapper.readValue(json, typeReference);
        } catch (IOException ex) {
            throw new RuntimeException("json -> object 异常", ex);
        }
    }

    /** json -> list[对象] */
    public static <T> List<T> jsonToList(String json, Class<T> clazz) {
        if (null == json) {
            return null;
        }

        try {
            JavaType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, clazz);
            return objectMapper.readValue(json, javaType);
        } catch (IOException ex) {
            throw new RuntimeException("json -> object 异常", ex);
        }
    }

    /** 对象拷贝, 通过json来进行 */
    public static <T extends BaseSerializable> T objectCopy(BaseSerializable src, Class<T> dstClass) {
        String srcStr = src.toString();
        T dst = JsonSerializer.jsonToObj(srcStr, dstClass);
        return dst;
    }


    /** json -> list[对象] */
    public static <T> String list2String(Collection<T> list) {
        return objectToJson(list);
    }

}
